// 路由守卫

import type { RouteRecordNormalized, RouteRecordRaw, Router } from 'vue-router'
import NProgress from 'nprogress'
import { ElMessage } from 'element-plus'
import { UserInfoEnum } from '@/enum'

declare module 'vue-router' {
  interface RouteMeta {
    /** 页面标题 */
    title?: string
    /** 页面权限 */
    power: string
  }
}

const whiteList = [
  /^\/login(?:\/\?)?$/i,
  /^\/404$/,
  /^\/test$/i,
  /^\/system-navigation$/i,
]

export function getFirstMenuPath(menu: RouteRecordRaw[]): string {
  for (const m of menu) {
    if (m.meta?.type === 4)
      continue
    if (m.component)
      return m.path
    if (m.component === null && m.children?.length === 0)
      continue
    if (m.children && m.children.length > 0) {
      return getFirstMenuPath(m.children)
    }
    else {
      return m.path
    }
  }
  return ''
}

function registerRouteGuard(router: Router) {
  const hasRoute = (
    path: string,
    routers: Array<RouteRecordNormalized | RouteRecordRaw> = router.getRoutes(),
  ): boolean =>
    routers.some((route) => {
      const _path = route.path ?? route.redirect
      // ! 去除空目录的情况
      if (
        !(route?.components || (route as any)?.component)
        && route.children?.length === 0
      ) {
        return false
      }
      if (_path === path) {
        return true
      }
      if (route.children && route.children.length > 0) {
        return hasRoute(path, route.children)
      }
      return false
    })
  /**
   * 全局前置守卫
   */
  router.beforeEach(async (to: any, _: any, next: any) => {
    const { fetchPermissionRoutes, addRemoveRouteFuns } = useUserStore()
    const { abortAxios } = usePageAjaxStore()
    const { has, pushHistory } = useKeepPageStore()
    abortAxios()
    const { path } = to
    pushHistory(path)
    // 开启进度条
    !has(path) && NProgress.start()

    const isToken = localStorage.getItem(UserInfoEnum.TOKEN)

    if (whiteList.some(v => v.test(path))) {
      next()
    }
    else if (!isToken) {
      path !== '/' && ElMessage.info('请登录后再试！')
      next('/login')
    }
    else {
      if (hasRoute(path)) {
        next()
      }
      else {
        const handlerPermissionRoutes = fetchPermissionRoutes()

        // 处理本地缓存丢失情况
        if (handlerPermissionRoutes[0]?.children?.length === 0) {
          ElMessage.info('用户过期请重新登录！')
          next({
            path: '/login',
            replace: true,
          })
          return
        }

        if (!hasRoute(path, handlerPermissionRoutes) && path !== '/') {
          // 自动跳转到404页面
          next({
            path: '/404',
            replace: true,
          })
        }
        else if (path === '/') {
          let redirectPath
          if (handlerPermissionRoutes[1]) {
            redirectPath = handlerPermissionRoutes[1].path

            const rootPath = getFirstMenuPath(
              handlerPermissionRoutes[0]!.children!,
            )

            useUserStore().setRootPath(rootPath)
          }
          else {
            redirectPath = getFirstMenuPath(
              handlerPermissionRoutes[0]!.children!,
            )

            useUserStore().setRootPath(redirectPath)
          }

          if (['/layout'].includes(redirectPath)) {
            next({
              path: '/system-navigation',
              replace: true,
            })
            return
          }
          if (redirectPath) {
            next({
              path: redirectPath,
              replace: true,
            })
            return
          }
          next({
            path: '/404',
            replace: true,
          })
        }
        else {
          handlerPermissionRoutes.forEach((item) => {
            try {
              addRemoveRouteFuns(router.addRoute(item))
            }
            catch (e) {
              console.log(e)
            }
          })
          next(path)
        }
      }
    }
  })

  /**
   * 全局后置守卫
   */
  router.afterEach((to) => {
    const { meta } = to
    const { setAnimateState } = useLayoutStore()
    const appName = APP_TITLE || import.meta.env.VITE_BASE_TITLE
    // 完成进度条
    NProgress.done()
    // 关闭全局动画
    setAnimateState(false)
    // 改标题,监控上报一些基础信息
    if (meta?.title) {
      document.title = `${appName}-${meta?.title}`
    }
    else {
      document.title = appName
    }
  })
}

export default registerRouteGuard
